package com.thread.park;

import lombok.extern.java.Log;
import org.springframework.stereotype.Service;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.LockSupport;

/**
 * @author lyp
 * 审核任务监控实现类
 */
@Log
@Service("TaskMonitorServiceImpl")
public class TaskMonitorServiceImpl {

	//总任务状态缓存表
	private List<TaskStatusBean> totalStatus = new ArrayList<>();
	//审核柜员任务处理缓存表
	private Map<String, UserTaskCountDto> userTaskMap = new ConcurrentHashMap<>();
	//监控工作线程引用
	private static MonitorWorkThread workThread = null;

	@PostConstruct
	private void initialize() {
		//实例化之后执行的初始化动作，用于启动值守监控线程来刷新加载数据
		workThread = new MonitorWorkThread();
		workThread.setDaemon(true);
		workThread.setName("AuthTaskMonitor");
		workThread.start();
	}

	/**
	 * 此为对外提供方法用于外部根据监控用户号获取内存中缓存的监控数据
	 *
	 * @param userno 监控用户号
	 * @return map key1:totalStatus key2:userno
	 * @throws Exception
	 */
	public Map<String, Object> monitorDataByUser(String userno) throws Exception {
		if (null == userno || "".equals(userno)) {
			return null;
		}
		Map<String, Object> retMap = new HashMap<>();
		if (null != workThread) {
			//每次请求都去看看异步值守线程是否需求唤醒
			workThread.unPack();
		}
		retMap.put("totalStatus", totalStatus);
		if (userTaskMap.containsKey(userno)) {
			retMap.put(userno, userTaskMap.get(userno));
		} else {
			UserTaskCountDto dto = new UserTaskCountDto(userno);
			retMap.put(userno, dto);
		}
		return retMap;
	}

	/**
	 * 从数据库中加载内存数据至内存
	 */
	private void loadDataFromDB() throws Exception {
		log.info("开始从数据库中加载任务监控数据...");
		//do something about business....
		log.info("从数据库中加载任务监控数据完毕...");
	}


	/**
	 * 清理监控缓存数据map
	 */
	public void clearMonitorCache() {
		this.totalStatus.clear();
		this.userTaskMap.clear();
	}

	private class TaskStatusBean {
	}

	private class UserTaskCountDto {
		public UserTaskCountDto(final String userno) {

		}
	}

	class MonitorWorkThread extends Thread {
		//当前线程停车标志
		private volatile boolean isPark = false;

		//工作线程默认一秒钟加载一次,count即为工作监控线程每一次unpack之后会继续工作的时间，此值可根据实际需求配置化
		private int maxWorkCount = 300;

		@Override
		public void run() {
			int indexCount = 0;
			log.info("成功启动审核任务监控工作线程，当前工作线程每次unpack连续工作的时间设定为" + maxWorkCount + "秒");
			while (true) {
				if (indexCount >= maxWorkCount) {
					log.info("当前监控工作线程已到达连续工作时间设定上限，现在进入pack休眠状态");
					isPark = true;
					indexCount = 0;
					LockSupport.park();
				}
				//从数据库中加载数据至内存
				try {
					 loadDataFromDB();
				} catch (Exception e1) {
					log.warning("从数据库中加载监控数据至内存发生异常");
				}
				try {
					TimeUnit.SECONDS.sleep(1);
				} catch (InterruptedException e) {
					log.warning("工作线程被异常中断唤醒");
				}
				indexCount++;
			}
		}

		/**
		 * 假如当前线程正在运行状态，donothing
		 */
		public void unPack() {
			if (isPark) {
				//唤醒当前监控工作线程，此处有并发唤醒动作需加锁
				synchronized (this) {
					isPark = false;
					LockSupport.unpark(this);
					log.info("当前监控工作线程已被唤醒");
				}
			}
		}
	}
}
